package com.igda.tihbms.controllers;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

import com.igda.tihbms.data.Bullet;
import com.igda.tihbms.data.Enemy;
import com.igda.tihbms.data.Rock;

public final class LogicController {

	// **** static variables ****
	public static interface GameStates {
		byte MENU = 0;
		byte PAUSE = 1;
		byte PLAYING = 2;
		byte EXIT = 3;
	}

	private static final long TICK = 50;
	// **** end of static variables ****

	private final Context context;

	private PaintThread paintThread;

	private byte state;

	private final EventsController eventsController;
	private final ObjectsController objectsController;
	private final ImagesController imagesController;

	private float posX;
	private float posY;

	private float clicX;
	private float clicY;
	private float shipWidth;
	private float bulletWidth;

	public LogicController(SurfaceHolder holder, Context context) {
		this.state = GameStates.MENU;
		this.eventsController = new EventsController();
		this.objectsController = new ObjectsController(this);
		this.imagesController = new ImagesController();
		this.context = context;

		this.state = GameStates.PLAYING;
	}

	public byte getState() {
		return state;
	}

	public void screenVisible(SurfaceHolder holder) {
		if (this.state == GameStates.PAUSE) {
			this.state = GameStates.PLAYING;
			this.paintThread = new PaintThread(this.context, holder, this);
			this.paintThread.start();
		} else {
			this.paintThread = new PaintThread(context, holder, this);
			this.paintThread.start();
		}
	}

	public void screenDestroyed() {
		boolean retry = true;
		this.state = GameStates.PAUSE;
		while (retry) {
			try {
				this.paintThread.join();
				retry = false;
			} catch (InterruptedException e) {
			}
		}
	}

	public void init(Resources resources) {
		this.imagesController.init(resources);
		this.objectsController.init(resources, this.imagesController);

		this.shipWidth = this.objectsController.getShipWidth();
		this.bulletWidth = this.imagesController.getBulletWidth();
	}

	public void gameLoop() {
		long time;
		while (this.state != GameStates.EXIT) {
			time = System.currentTimeMillis();
			gameLoop();
			time = TICK - System.currentTimeMillis() - time;

			if (time > 0) {
				try {
					Thread.sleep(time);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	int CLICK_WEIGHT = 4;
	int TOTAL_WEIGHT = 32;

	public void update() {
		if (this.posX != this.clicX) {
			if (Math.abs(this.posX - this.clicX) < 1) {
				this.posX = this.clicX;
			} else {
				this.posX = (this.clicX * CLICK_WEIGHT / TOTAL_WEIGHT)
						+ (this.posX * (TOTAL_WEIGHT - CLICK_WEIGHT) / TOTAL_WEIGHT);
			}
		}
		if (this.posY != this.clicY) {
			if (Math.abs(this.posY - this.clicY) < 1) {
				this.posY = this.clicY;
			} else {
				this.posY = (this.clicY * CLICK_WEIGHT / TOTAL_WEIGHT)
						+ (this.posY * (TOTAL_WEIGHT - CLICK_WEIGHT) / TOTAL_WEIGHT);
			}
		}

		if (Math.random() < 0.01) {
			this.crateRock();
		}

		if (Math.random() < 0.002) {
			this.crateEnemy();
		}

		this.objectsController.updateCraftLocation(this.posX, this.posY);
		this.objectsController.tick();
	}

	private void crateRock() {
		int selectedRock = (int) (Math.random() * 2);

		Bitmap rockBitmap = this.imagesController.getRock(selectedRock);
		this.objectsController.addObject(new Rock(150, 0, rockBitmap));
	}

	private void crateEnemy() {
		int selectedEnemy = (int) (Math.random() * 2);

		Bitmap enemyBitmap = this.imagesController.getShip();
		this.objectsController.addObject(new Enemy(250, 15, enemyBitmap));
	}

	public void draw(Canvas c) {
		this.objectsController.draw(c);
	}

	public void input(MotionEvent event) {
		this.clicX = event.getX() - this.shipWidth / 2;
		this.clicY = event.getY();
	}

	public void createBullet(float posX, float posY) {
		Bullet bullet = new Bullet(posX - this.bulletWidth / 2 + this.shipWidth
				/ 2, posY, this.imagesController.getBullet());
		this.objectsController.addObject(bullet);
	}
}
